/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.rbac.service.account.impl;

import cn.hutool.core.util.RandomUtil;
import com.google.common.base.Strings;
import com.je.auth.AuthLoginManager;
import com.je.auth.AuthSessionTemplate;
import com.je.common.auth.impl.Department;
import com.je.common.auth.impl.DepartmentUser;
import com.je.common.auth.impl.PlatformOrganization;
import com.je.common.auth.impl.RealOrganizationUser;
import com.je.common.auth.impl.account.Account;
import com.je.common.auth.impl.role.Role;
import com.je.common.base.DynaBean;
import com.je.common.base.service.MetaService;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.message.exception.MessageSendException;
import com.je.message.rpc.NoteRpcService;
import com.je.message.vo.CodeEnum;
import com.je.message.vo.NoteMsg;
import com.je.meta.rpc.setting.MetaSystemSettingRpcService;
import com.je.rbac.exception.AccountException;
import com.je.rbac.exception.LoginException;
import com.je.rbac.rpc.PermissionRpcService;
import com.je.rbac.service.account.RbacAccountService;
import com.je.rbac.service.account.RbacLoginService;
import com.je.rbac.service.log.RbacLoginLogService;
import com.je.rbac.service.organization.OrgType;
import com.je.rbac.service.organization.RbacOrganizationService;
import com.je.rbac.service.organization.RbacRealOrganizationService;
import com.je.rbac.service.role.RbacRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;

@Service
public class RbacLoginServiceImpl implements RbacLoginService {

    /**
     * 验证码的key
     */
    private static final String CAPTCHA_KEY_TEMPLATE = "feedBackCaptcha/%s/%s";

    @Autowired
    private AuthLoginManager authLoginManager;
    @Autowired
    private MetaService metaService;
    @Autowired
    private RbacOrganizationService rbacOrganizationService;
    @Autowired
    private RbacRoleService rbacRoleService;
    @Autowired
    private RbacAccountService rbacAccountService;
    @Autowired
    private RbacRealOrganizationService rbacRealOrganizationService;
    @Autowired
    private AuthSessionTemplate authSessionTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RbacLoginLogService rbacLoginLogService;
    @Autowired
    private MetaSystemSettingRpcService metaSystemSettingRpcService;
    @Autowired
    private PermissionRpcService permissionRpcService;
    @Autowired
    private NoteRpcService noteRpcService;

    @Override
    public List<Map<String, Object>> checkDepartment(DynaBean accountBean) throws LoginException {
        //检查机构类型，如果是部门，并且没有传递部门ID，则检查是否是多部门
        DynaBean orgBean = metaService.selectOne("JE_RBAC_ORG", ConditionsWrapper.builder().eq("JE_RBAC_ORG_ID", accountBean.getStr("SY_ORG_ID")));
        if (!OrgType.DEPARTMENT_ORG_ID.getCode().equals(orgBean.getStr("JE_RBAC_ORG_ID"))) {
            return null;
        }
        List<DynaBean> vDeptUserList = metaService.select("JE_RBAC_VDEPTUSER", ConditionsWrapper.builder().eq("JE_RBAC_USER_ID", accountBean.getStr("USER_ASSOCIATION_ID")));
        if (vDeptUserList == null || vDeptUserList.size() <= 0) {
            throw new LoginException("获取人员部门异常");
        }

        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> eachMap;
        for (DynaBean eachDeptUser : vDeptUserList) {
            eachMap = new HashMap<>();
            eachMap.put("name", eachDeptUser.getStr("DEPARTMENT_NAME"));
            eachMap.put("id", eachDeptUser.getStr("JE_RBAC_DEPARTMENT_ID"));
            list.add(eachMap);
        }
        return list;
    }

    @Override
    public DynaBean findAccountDept(String accountId, String deptId) {
        DynaBean accountDept = metaService.selectOne("JE_RBAC_VACCOUNTDEPT",
                ConditionsWrapper.builder().eq("JE_RBAC_ACCOUNT_ID", accountId).eq("ACCOUNTDEPT_DEPT_ID", deptId));
        return accountDept;
    }

    @Override
    public boolean checkLogin() {
        return authLoginManager.isLogin();
    }

    @Override
    public boolean checkRandom(DynaBean accountBean, String captchaNum, String device) {
        String key = String.format(CAPTCHA_KEY_TEMPLATE, accountBean.getStr("ACCOUNT_PHONE"), captchaNum);
        Object num = redisTemplate.opsForValue().get(key);
        if (num == null) {
            return false;
        }
        if (!num.equals(captchaNum)) {
            return false;
        }
        return true;
    }

    @Override
    public String sendRandom(DynaBean accountBean, String device) throws LoginException {
        String captureCode = RandomUtil.randomNumbers(6);
        String timeout = metaSystemSettingRpcService.requireSettingValue("JE_SMS_TIMEOUT");
        String captureString = "您好，您的验证码为：" + captureCode + "，验证码有效时长" + timeout + "秒，如非本人操作，请忽略此短信";
        try {
            NoteMsg noteMsg = new NoteMsg();
            noteMsg.setFromUser("系统");
            noteMsg.setToUser(accountBean.getStr("ACCOUNT_NAME"));
            noteMsg.setContext(captureString);
            noteMsg.setPhoneNumber(accountBean.getStr("ACCOUNT_PHONE"));
            noteMsg.setFl("短信登录");
            noteMsg.setMsgCode(captureCode);
            int codeCount = noteRpcService.sendNoteCode(noteMsg);
            if (codeCount != CodeEnum.SUCCESS.getCode()) {
                throw new LoginException(CodeEnum.getMessage(codeCount));
            }
        } catch (MessageSendException e) {
            throw new LoginException("短信发送失败，请联系管理员！");
        }
        return captureCode;
    }

    @Override
    public String login(String tenantId, String departmentId, DynaBean accountBean, String device, String operation) throws AccountException {
        String orgId = accountBean.getStr("SY_ORG_ID");
        //真实用户ID
        String userId = accountBean.getStr("USER_ASSOCIATION_ID");

        //账号角色关联
        List<DynaBean> accountRoleBeans = metaService.select("JE_RBAC_VACCOUNTROLE", ConditionsWrapper.builder()
                .eq("JE_RBAC_ACCOUNT_ID", accountBean.getStr("JE_RBAC_ACCOUNT_ID")));

        List<String> roleIdList = new ArrayList<>();
        if (accountRoleBeans != null && !accountRoleBeans.isEmpty()) {
            for (DynaBean eachBean : accountRoleBeans) {
                roleIdList.add(eachBean.getStr("ACCOUNTROLE_ROLE_ID"));
            }
        }

        //构建角色
        List<Role> roleList = rbacRoleService.buildRoleByIds(roleIdList);
        //如果是部门类型则需要构建真实机构和真实人员
        RealOrganizationUser realOrganizationUser = null;
        DynaBean orgBean = rbacOrganizationService.findById(orgId);
        if (OrgType.DEPARTMENT_ORG_ID.getCode().equals(orgBean.getStr("JE_RBAC_ORG_ID"))) {
            Department realOrganization = new Department();
            realOrganizationUser = new DepartmentUser(realOrganization);
            rbacRealOrganizationService.fillOrganization(departmentId, realOrganization);
            rbacRealOrganizationService.fillRealUser(orgId, userId, realOrganizationUser);
        } else {
            //外部机构用户构建真实用户
            realOrganizationUser = new RealOrganizationUser();
            rbacRealOrganizationService.fillRealUser(orgId, userId, realOrganizationUser);
        }

        //构建账号机构
        PlatformOrganization platformOrganization = rbacOrganizationService.buildById(accountBean.getStr("SY_ORG_ID"));
        Account account = rbacAccountService.buildAccountModel(accountBean, realOrganizationUser, roleList, new HashSet<>());
        account.setPlatformOrganization(platformOrganization);
        if (accountBean.containsKey("SY_TENANT_ID") && Strings.isNullOrEmpty(accountBean.getStr("SY_TENANT_ID"))) {
            account.setTenantId(accountBean.getStr("SY_TENANT_ID"));
            account.setTenantName(accountBean.getStr("SY_TENANT_NAME"));
        }
        authLoginManager.login(accountBean.getStr("JE_RBAC_ACCOUNT_ID"));
        //TODO saas保存用户租户id暂时去掉
        account.setTenantId("");
        authSessionTemplate.set(authLoginManager.getSession(), "account", account);
        rbacLoginLogService.saveLoginLog(departmentId, accountBean, device, operation);
        return authLoginManager.getTokenValue();
    }

    @Override
    public boolean logout() {
        authLoginManager.logout();
        return authLoginManager.isLogin();
    }

    @Override
    public void logoutByToken(String token) {
        authLoginManager.logoutByTokenValue(token);
    }

    @Override
    public boolean kickout(String userId, String device) {
        authLoginManager.kickout(userId, device);
        return authLoginManager.isLogin();
    }

}
